#define _GNU_SOURCE
#include "app_device.h"
#include "app_common.h"
#include "app_message.h"
#include "app_mqtt.h"
#include "app_pool.h"
#include "log/log.h"
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>

#define BUFFER_SIZE 1024
static Device *device;
// 初始化设备
Device *app_device_init(char *filename)
{
    // 申请内存
    device = (Device *)malloc(sizeof(Device));
    // 初始化属性
    device->filename = filename;
    device->fd = open(filename,O_RDWR,0644);
    device->up_buffer = app_buffer_init(BUFFER_SIZE);
    device->down_buffer = app_buffer_init(BUFFER_SIZE);
    device->is_running = 0;
    device->last_write_time = 0;
    device->post_read = NULL;
    device->pre_write = NULL;
    // 初始化线程池
    
    app_pool_init(5);
    // 初始化mqtt客户端模块
    app_mqtt_init();

    return device;
}

// 发送远程消息的任务函数
int send_task_func(void *arg)
{
    Device *dev = (Device *)arg;
    // 从上行缓冲区读取数据
    char chars_buf[128];
    int len = app_buffer_read(device->up_buffer,chars_buf,sizeof(chars_buf));
    // 转换为json格式
    char *json = app_message_charsToJson(chars_buf,len);
    // 发送到远程
    int result = app_mqtt_send(json);
    if (result == -1)
    {
        log_error("send message to remote failed");
        return -1;
    }
    log_debug("send message to remote success:%s",json);
    return 0;

}

// 读线程函数
static void *read_thread_func(void *arg)
{
    // 不断读取串口文件中的数据
    while(device->is_running)
    {
        char data_buf[128];
        ssize_t data_len = read(device->fd,data_buf,sizeof(data_buf));
        // 如果读取到数据,则调用处理
        if(data_len > 0 && device->post_read)
        {
            data_len = device->post_read(data_buf,data_len);
        }
        if (data_len > 0)
        {
            // 将字符数组消息数据保存到上行缓冲区
            app_buffer_write(device->up_buffer,data_buf,data_len);

            // 将发送消息数据到远程的任务交给线程池处理
            app_pool_registerTask(send_task_func,device);
        }
    }

}

// 将下行缓冲区中的读取数据到串口文件的任务函数 =》线程池中的分线程调用
int write_task_func(void *arg)
{
    // 从下行缓冲区读取数据
    char chars_buf[128];
    int len = app_buffer_read(device->down_buffer,chars_buf,sizeof(chars_buf));
    // 如果有前置处理函数,则调用 => 转换为蓝牙格式数据
    if (len = -1)
    {
        log_error("read data from down buffer failed");
        return -1;
    } 
    if(device->pre_write)
    {
        len = device->pre_write(chars_buf,len);
    }
    // 如果与上一次写入时间间隔小于200ms,则等待相关时间
    long distance_time = app_common_getCurrentTime() - device->last_write_time;
    if (distance_time < 200)
    {
        usleep((200 - distance_time) * 1000);
    }

    // 写入串口文件
    ssize_t result = write(device->fd,chars_buf,len);
    if (result != len)
    {
        log_error("写入串口文件失败");
        return -1;
    }
    log_debug("写入串口文件成功:%.*s",len,chars_buf);
    device->last_write_time = app_common_getCurrentTime();
    return 0;
}

static int receive_msg_callback(char *json)
{
    // 将json数据转换为字符数组
    char chars_buf[128];
    int len = app_message_jsonToChars(json,chars_buf,sizeof(chars_buf));
    // 将字符数组消息数据保存到下行缓冲区
    app_buffer_write(device->down_buffer,chars_buf,len);
    // 将下行缓冲区中的读取数据到串口文件的任务交给线程池处理
    app_pool_registerTask(write_task_func,NULL);
    
    return 0;
}

// 启动设备
int app_device_start()
{
    if (device->is_running == 1)
    {
        log_debug("设备已经正在运行， 不用再次启动");
        return 0;
    }
    device->is_running = 1;
    // 启动读线程
    pthread_create(&device->read_thread,NULL,read_thread_func,NULL);
    // 注册接受远程消息的回调函数
    app_mqtt_registerRecvCallback(receive_msg_callback);

}

// 销毁设备
void app_device_destroy()
{
    // 关闭文件
    close(device->fd);
    // 释放缓冲区
    app_buffer_free(device->up_buffer);
    app_buffer_free(device->down_buffer);
    // 取消停止读线程
    pthread_cancel(device->read_thread);
    pthread_join(device->read_thread,NULL);
    // 释放device
    free(device);
    // 释放线程池
    app_pool_destroy();
    // 释放mqtt客户端模块
    app_mqtt_close();
}